package top.luoyuanxiang.mqtt.utils;

import cn.hutool.core.util.HexUtil;
import cn.hutool.crypto.symmetric.SM4;
import jakarta.validation.constraints.NotNull;
import lombok.experimental.UtilityClass;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.BiConsumer;
import java.util.function.Consumer;

/**
 * 报文单元测试
 *
 * @author luoyuanxiang
 */
@UtilityClass
public class BinaryDemoUtils {

    private final String privateKeyStr = "308193020100301306072a8648ce3d020106082a811ccf5501822d04793077020101042019f4082f2a5fc7d263b065df08dd0e804a1b3dde77f9345d42b6ee884f94d575a00a06082a811ccf5501822da14403420004998b50dc8843727651f85e8e8a722bd8ff98259c10835eed6c159830418f778d6451ecbbef637bb2de3321e98cf0e9b1a781b12cc629c7d922c5d495c07b689c";
    private final String publicKeyStr = "3059301306072a8648ce3d020106082a811ccf5501822d03420004998b50dc8843727651f85e8e8a722bd8ff98259c10835eed6c159830418f778d6451ecbbef637bb2de3321e98cf0e9b1a781b12cc629c7d922c5d495c07b689c";

    /**
     * 信息发布测试
     *
     * @param hexStr           十六进制 str
     * @param devicePrivateKey 设备私钥
     * @return {@link String}
     */
    public String taskTest(String hexStr, String devicePrivateKey) {
        StringBuilder str = commonProcess(hexStr, (stringBuilder, dataByte) -> {
            int startIndex = 0;
            // 信息发布任务ID长度
            byte[] bytes = BinaryUtil.subArray(dataByte, startIndex, 1);
            int taskLength = Jtt808Utils.byteToInt(bytes);
            System.err.println("信息发布任务ID长度 -- : " + taskLength);
            stringBuilder.append("信息发布任务ID长度 -- : ").append(taskLength);
            stringBuilder.append("\n");
            startIndex = startIndex + 1;

            // 信息发布任务ID
            bytes = BinaryUtil.subArray(dataByte, startIndex, taskLength);
            long taskId = Jtt808Utils.bcdBytes2Long(bytes);
            System.err.println("信息发布任务ID -- : " + taskId);
            stringBuilder.append("信息发布任务ID -- : ").append(taskId);
            stringBuilder.append("\n");
            startIndex = startIndex + taskLength;

            // 信息发布推送任务ID长度
            bytes = BinaryUtil.subArray(dataByte, startIndex, 1);
            int pushTaskLength = Jtt808Utils.byteToInt(bytes);
            System.err.println("信息发布推送任务ID长度 -- : " + pushTaskLength);
            stringBuilder.append("信息发布推送任务ID长度 -- : ").append(pushTaskLength);
            stringBuilder.append("\n");
            startIndex = startIndex + 1;

            // 信息发布推送任务ID
            bytes = BinaryUtil.subArray(dataByte, startIndex, pushTaskLength);
            long pushTaskID = Jtt808Utils.bcdBytes2Long(bytes);
            System.err.println("信息发布推送任务ID -- : " + pushTaskID);
            stringBuilder.append("信息发布推送任务ID -- : ").append(pushTaskID);
            stringBuilder.append("\n");
            startIndex = startIndex + pushTaskLength;

            // 资源文件秘钥
            bytes = BinaryUtil.subArray(dataByte, startIndex, 113);
            String resourceKey = Jtt808Utils.byte2Hex(bytes);
            byte[] bytes1 = KeyGenerateUtil.sm2Decrypt(devicePrivateKey, resourceKey);
            resourceKey = Jtt808Utils.bcdBytes2HexStr(bytes1);
            System.err.println("资源文件秘钥：" + resourceKey);
            stringBuilder.append("\n资源文件秘钥 -- : ").append(resourceKey);
            stringBuilder.append("\n");
            startIndex = startIndex + 113;

            // 置顶
            bytes = BinaryUtil.subArray(dataByte, startIndex, 1);
            int top = Jtt808Utils.byteToInt(bytes);
            System.err.println("置顶 -- ：" + top);
            stringBuilder.append("置顶 -- ：").append(top);
            stringBuilder.append("\n");
            startIndex = startIndex + 1;

            // 信息发布数据，动态密钥SM4加密后的数据
            dataByte = BinaryUtil.subArray(dataByte, startIndex, dataByte.length - startIndex - 1);

            startIndex = 0;
            // 区域数量
            bytes = BinaryUtil.subArray(dataByte, startIndex, 1);
            int regionCount = Jtt808Utils.bcdBytes2Int(bytes);
            System.err.println("区域数量 -- ：" + regionCount);
            stringBuilder.append("区域数量 -- ：").append(regionCount);
            stringBuilder.append("\n");

            // 初始化
            startIndex = startIndex + 1;
            for (int i = 0; i < regionCount; i++) {
                // 区域ID长度
                bytes = BinaryUtil.subArray(dataByte, startIndex, 1);
                int regionIdLength = Jtt808Utils.bcdBytes2Int(bytes);
                System.err.println("区域ID长度 -- ：" + regionIdLength);
                stringBuilder.append("区域ID长度 -- ：").append(regionIdLength);
                stringBuilder.append("\n");
                startIndex = startIndex + 1;

                // 区域ID
                bytes = BinaryUtil.subArray(dataByte, startIndex, regionIdLength);
                String s2 = new String(bytes, StandardCharsets.UTF_8);
                System.err.println("区域ID -- ：" + s2);
                stringBuilder.append("区域ID -- ：").append(s2);
                stringBuilder.append("\n");
                startIndex = startIndex + regionIdLength;

                // 节目数量
                bytes = BinaryUtil.subArray(dataByte, startIndex, 1);
                int programCount = Jtt808Utils.byteToInt(bytes);
                System.err.println("节目数量 -- ：" + programCount);
                stringBuilder.append("节目数量 -- ：").append(programCount);
                stringBuilder.append("\n");
                startIndex = startIndex + 1;

                for (int j = 0; j < programCount; j++) {
                    // 节目ID长度
                    bytes = BinaryUtil.subArray(dataByte, startIndex, 1);
                    int programIdLength = Jtt808Utils.byteToInt(bytes);
                    System.err.println("节目ID长度 -- ：" + programIdLength);
                    stringBuilder.append("节目ID长度 -- ：").append(programIdLength);
                    stringBuilder.append("\n");
                    startIndex = startIndex + 1;

                    // 节目ID
                    bytes = BinaryUtil.subArray(dataByte, startIndex, programIdLength);
                    long s4 = Jtt808Utils.bcdBytes2Long(bytes);
                    System.err.println("节目ID -- ：" + s4);
                    stringBuilder.append("节目ID -- ：").append(s4);
                    stringBuilder.append("\n");
                    startIndex = startIndex + programIdLength;

                    // 节目名称长度
                    bytes = BinaryUtil.subArray(dataByte, startIndex, 1);
                    int programNameLength = Jtt808Utils.byteToInt(bytes);
                    System.err.println("节目名称长度 -- ：" + programNameLength);
                    stringBuilder.append("节目名称长度 -- ：").append(programNameLength);
                    stringBuilder.append("\n");
                    startIndex = startIndex + 1;

                    // 节目名称
                    bytes = BinaryUtil.subArray(dataByte, startIndex, programNameLength);
                    String s5 = new String(bytes, StandardCharsets.UTF_8);
                    System.err.println("节目名称 -- ：" + s5);
                    stringBuilder.append("节目名称 -- ：").append(s5);
                    stringBuilder.append("\n");
                    startIndex = startIndex + programNameLength;

                    // 节目播放开始日期
                    bytes = BinaryUtil.subArray(dataByte, startIndex, 3);
                    String programStartDate = Jtt808Utils.bcdBytes2HexStr(bytes);
                    System.err.println("节目播放开始日期 -- ：" + programStartDate);
                    stringBuilder.append("节目播放开始日期 -- ：").append(programStartDate);
                    stringBuilder.append("\n");
                    startIndex = startIndex + 3;

                    // 节目播放结束日期
                    bytes = BinaryUtil.subArray(dataByte, startIndex, 3);
                    String programEndDate = Jtt808Utils.bcdBytes2HexStr(bytes);
                    System.err.println("节目播放结束日期 -- ：" + programEndDate);
                    stringBuilder.append("节目播放结束日期 -- ：").append(programEndDate);
                    stringBuilder.append("\n");
                    startIndex = startIndex + 3;

                    // 节目指定周几播放
                    bytes = BinaryUtil.subArray(dataByte, startIndex, 1);
                    String programWeek = Jtt808Utils.byte2Hex(bytes);
                    String programmed = programWeek(Jtt808Utils.hex2Binary(programWeek));
                    System.err.println("节目指定周几播放 -- ：" + programmed);
                    stringBuilder.append("节目指定周几播放 -- ：").append(programmed);
                    stringBuilder.append("\n");
                    startIndex = startIndex + 1;

                    // 节目播放开始时间
                    bytes = BinaryUtil.subArray(dataByte, startIndex, 3);
                    String programStartTime = Jtt808Utils.bcdBytes2HexStr(bytes);
                    System.err.println("节目播放开始时间 -- ：" + programStartTime);
                    stringBuilder.append("节目播放开始时间 -- ：").append(programStartTime);
                    stringBuilder.append("\n");
                    startIndex = startIndex + 3;

                    // 节目播放结束时间
                    bytes = BinaryUtil.subArray(dataByte, startIndex, 3);
                    String programEndTime = Jtt808Utils.bcdBytes2HexStr(bytes);
                    System.err.println("节目播放结束时间 -- ：" + programEndTime);
                    stringBuilder.append("节目播放结束时间 -- ：").append(programEndTime);
                    stringBuilder.append("\n");
                    startIndex = startIndex + 3;

                    // 节目播放次数
                    bytes = BinaryUtil.subArray(dataByte, startIndex, 1);
                    int programDuration = Jtt808Utils.bcdBytes2Int(bytes);
                    System.err.println("节目播放次数 -- ：" + programDuration);
                    stringBuilder.append("节目播放次数 -- ：").append(programDuration);
                    stringBuilder.append("\n");
                    startIndex = startIndex + 1;

                    // 节目排序
                    bytes = BinaryUtil.subArray(dataByte, startIndex, 1);
                    int programSort = Jtt808Utils.bcdBytes2Int(bytes);
                    System.err.println("节目排序 -- ：" + programSort);
                    stringBuilder.append("节目排序 -- ：").append(programSort);
                    stringBuilder.append("\n");
                    startIndex = startIndex + 1;

                    // 资源数量
                    bytes = BinaryUtil.subArray(dataByte, startIndex, 1);
                    int resourceCount = Jtt808Utils.bcdBytes2Int(bytes);
                    System.err.println("资源数量 -- ：" + resourceCount);
                    stringBuilder.append("资源数量 -- ：").append(resourceCount);
                    stringBuilder.append("\n");
                    startIndex = startIndex + 1;

                    for (int k = 0; k < resourceCount; k++) {
                        // 资源类型
                        bytes = BinaryUtil.subArray(dataByte, startIndex, 1);
                        int resourceType = Jtt808Utils.byteToInt(bytes);
                        System.err.println("资源类型 -- ：" + resourceType);
                        stringBuilder.append("资源类型 -- ：").append(resourceType);
                        stringBuilder.append("\n");
                        startIndex = startIndex + 1;

                        // 资源ID长度
                        bytes = BinaryUtil.subArray(dataByte, startIndex, 1);
                        int resourceIdLength = Jtt808Utils.byteToInt(bytes);
                        System.err.println("资源ID长度 -- ：" + resourceIdLength);
                        stringBuilder.append("资源ID长度 -- ：").append(resourceIdLength);
                        stringBuilder.append("\n");
                        startIndex = startIndex + 1;

                        // 资源ID
                        bytes = BinaryUtil.subArray(dataByte, startIndex, resourceIdLength);
                        System.err.println("资源ID -- ：" + Jtt808Utils.bcdBytes2Long(bytes));
                        stringBuilder.append("资源ID -- ：").append(Jtt808Utils.bcdBytes2Long(bytes));
                        stringBuilder.append("\n");
                        startIndex = startIndex + resourceIdLength;

                        // 资源播放顺序
                        bytes = BinaryUtil.subArray(dataByte, startIndex, 1);
                        int resourceSort = Jtt808Utils.bcdBytes2Int(bytes);
                        System.err.println("资源播放顺序 -- ：" + resourceSort);
                        stringBuilder.append("资源播放顺序 -- ：").append(resourceSort);
                        stringBuilder.append("\n");
                        startIndex = startIndex + 1;

                        // 文本内容长度，为0表示没有文本内容
                        bytes = BinaryUtil.subArray(dataByte, startIndex, 2);
                        int textLength = Jtt808Utils.bcdBytes2Int(bytes);
                        System.err.println("文本内容长度 -- ：" + textLength);
                        stringBuilder.append("文本内容长度 -- ：").append(textLength);
                        stringBuilder.append("\n");
                        startIndex = startIndex + 2;

                        if (textLength > 0) {
                            // 文本内容
                            bytes = BinaryUtil.subArray(dataByte, startIndex, textLength);
                            String s = Jtt808Utils.byte2Hex(bytes);
                            // 解密
                            String sm4Decrypt = KeyGenerateUtil.sm4Decrypt(resourceKey, s);
                            System.err.println("文本内容 -- ：" + sm4Decrypt);
                            stringBuilder.append("文本内容 -- ：").append(sm4Decrypt);
                            stringBuilder.append("\n");
                            startIndex = startIndex + textLength;
                        }

                        // 图片|视频的持续时长
                        bytes = BinaryUtil.subArray(dataByte, startIndex, 4);
                        int duration = Jtt808Utils.bcdBytes2Int(bytes);
                        System.err.println("图片|视频的持续时长 -- ：" + duration);
                        stringBuilder.append("图片|视频的持续时长 -- ：").append(duration);
                        stringBuilder.append("\n");
                        startIndex = startIndex + 4;

                        // 文字滚动倍数长度，为空表示没有文字滚动
                        bytes = BinaryUtil.subArray(dataByte, startIndex, 1);
                        int textScrollLength = Jtt808Utils.bcdBytes2Int(bytes);
                        System.err.println("文字滚动倍数长度 -- ：" + textScrollLength);
                        stringBuilder.append("文字滚动倍数长度 -- ：").append(textScrollLength);
                        stringBuilder.append("\n");
                        startIndex = startIndex + 1;

                        if (textScrollLength > 0) {
                            // 文字滚动倍数
                            bytes = BinaryUtil.subArray(dataByte, startIndex, textScrollLength);
                            System.err.println("文字滚动倍数 -- ：" + new String(bytes, StandardCharsets.UTF_8));
                            stringBuilder.append("文字滚动倍数 -- ：").append(new String(bytes, StandardCharsets.UTF_8));
                            stringBuilder.append("\n");
                            startIndex = startIndex + textScrollLength;
                        }

                        // 文字播放间隔时间，为0表示没有文字播放间隔
                        bytes = BinaryUtil.subArray(dataByte, startIndex, 2);
                        int textInterval = Jtt808Utils.bcdBytes2Int(bytes);
                        System.err.println("文字播放间隔时间 -- ：" + textInterval);
                        stringBuilder.append("文字播放间隔时间 -- ：").append(textInterval);
                        stringBuilder.append("\n");
                        startIndex = startIndex + 2;

                        // 文件切片数量，1表示未切片，0表示无资源文件，大于1表示切片数量
                        bytes = BinaryUtil.subArray(dataByte, startIndex, 1);
                        int sliceCount = Jtt808Utils.byteToInt(bytes);
                        System.err.println("文件切片数量 -- ：" + sliceCount);
                        stringBuilder.append("文件切片数量 -- ：").append(sliceCount);
                        stringBuilder.append("\n");
                        startIndex = startIndex + 1;

                        for (int i1 = 0; i1 < sliceCount; i1++) {
                            // 文件地址长度
                            bytes = BinaryUtil.subArray(dataByte, startIndex, 2);
                            int fileAddressLength = Jtt808Utils.bcdBytes2Int(bytes);
                            System.err.println("文件地址长度 -- ：" + fileAddressLength);
                            stringBuilder.append("文件地址长度 -- ：").append(fileAddressLength);
                            stringBuilder.append("\n");
                            startIndex = startIndex + 2;

                            // 文件地址
                            bytes = BinaryUtil.subArray(dataByte, startIndex, fileAddressLength);
                            System.err.println("文件地址 -- ：" + new String(bytes, StandardCharsets.UTF_8));
                            stringBuilder.append("文件地址 -- ：").append(new String(bytes, StandardCharsets.UTF_8));
                            stringBuilder.append("\n");
                            startIndex = startIndex + fileAddressLength;

                            // 文件签名
                            bytes = BinaryUtil.subArray(dataByte, startIndex, 32);
                            String sign = Jtt808Utils.byte2Hex(bytes);
                            System.err.println("文件签名 -- ：" + sign);
                            stringBuilder.append("文件签名 -- ：").append(sign);
                            stringBuilder.append("\n");
                            startIndex = startIndex + 32;
                        }

                        // 字体倍率长度
                        bytes = BinaryUtil.subArray(dataByte, startIndex, 1);
                        int fontScaleLength = Jtt808Utils.byteToInt(bytes);
                        System.err.println("字体倍率长度 -- ：" + fontScaleLength);
                        stringBuilder.append("字体倍率长度 -- ：").append(fontScaleLength);
                        stringBuilder.append("\n");
                        startIndex = startIndex + 1;

                        if (fontScaleLength > 0) {
                            // 字体倍率
                            bytes = BinaryUtil.subArray(dataByte, startIndex, fontScaleLength);
                            System.err.println("字体倍率 -- ：" + new String(bytes, StandardCharsets.UTF_8));
                            stringBuilder.append("字体倍率 -- ：").append(new String(bytes, StandardCharsets.UTF_8));
                            stringBuilder.append("\n");
                            startIndex = startIndex + fontScaleLength;
                        }
                    }
                }
            }
        });

        return str.toString();
    }

    /**
     * 应急任务测试
     *
     * @param hexStr           十六进制 str
     * @param devicePrivateKey 设备私钥
     * @return {@link String}
     */
    public String emergencyTest(String hexStr, String devicePrivateKey) {
        StringBuilder str = commonProcess(hexStr, (strBuilder, dataBytes) -> {
            int startIndex = 0;
            // 应急任务ID长度
            byte[] bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            int emergencyIdLength = Jtt808Utils.bcdBytes2Int(bytes);
            System.err.println("应急任务ID长度 -- ：" + emergencyIdLength);
            strBuilder.append("应急任务ID长度 -- ：").append(emergencyIdLength).append("\n");
            startIndex = startIndex + 1;

            // 应急任务ID
            bytes = BinaryUtil.subArray(dataBytes, startIndex, emergencyIdLength);
            System.err.println("应急任务ID -- ：" + Jtt808Utils.bcdBytes2Long(bytes));
            strBuilder.append("应急任务ID -- ：").append(Jtt808Utils.bcdBytes2Long(bytes)).append("\n");
            startIndex = startIndex + emergencyIdLength;

            // 应急推送任务ID长度
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            int emergencyPushIdLength = Jtt808Utils.byteToInt(bytes);
            System.err.println("应急推送任务ID长度 -- ：" + emergencyPushIdLength);
            strBuilder.append("应急推送任务ID长度 -- ：").append(emergencyPushIdLength).append("\n");
            startIndex = startIndex + 1;

            // 应急推送任务ID
            bytes = BinaryUtil.subArray(dataBytes, startIndex, emergencyPushIdLength);
            System.err.println("应急推送任务ID -- ：" + Jtt808Utils.bcdBytes2Long(bytes));
            strBuilder.append("应急推送任务ID -- ：").append(Jtt808Utils.bcdBytes2Long(bytes)).append("\n");
            startIndex = startIndex + emergencyPushIdLength;

            // 动态秘钥
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 113);
            String keyEncrypt = Jtt808Utils.byte2Hex(bytes);
            System.err.println("动态秘钥加密 -- : " + keyEncrypt);
            strBuilder.append("动态秘钥加密 -- : ").append(keyEncrypt).append("\n");
            // 动态秘钥解密
            String keyDecrypt = Jtt808Utils.byte2Hex(KeyGenerateUtil.sm2Decrypt(devicePrivateKey, keyEncrypt));
            System.err.println("动态秘钥解密 -- : " + keyDecrypt);
            strBuilder.append("动态秘钥解密 -- : ").append(keyDecrypt).append("\n");
            startIndex = startIndex + 113;

            // 数据解密
            dataBytes = BinaryUtil.subArray(dataBytes, startIndex, dataBytes.length - startIndex - 1);
            startIndex = 0;

            // 应急任务类型
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            int emergencyType = Jtt808Utils.bcdBytes2Int(bytes);
            System.err.println("应急任务类型 -- ：" + emergencyType);
            strBuilder.append("应急任务类型 -- ：").append(emergencyType).append("\n");
            startIndex = startIndex + 1;

            // 持续时长
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 3);
            int duration = Jtt808Utils.bcdBytes2Int(bytes);
            System.err.println("持续时长 -- ：" + duration);
            strBuilder.append("持续时长 -- ：").append(duration).append("\n");
            startIndex = startIndex + 3;

            // 应急内容长度
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 2);
            int emergencyContentLength = Jtt808Utils.bcdBytes2Int(bytes);
            System.err.println("应急内容长度 -- ：" + emergencyContentLength);
            strBuilder.append("应急内容长度 -- ：").append(emergencyContentLength).append("\n");
            startIndex = startIndex + 2;

            // 应急内容
            bytes = BinaryUtil.subArray(dataBytes, startIndex, emergencyContentLength);
            String s = Jtt808Utils.byte2Hex(bytes);
            String sm4Decrypt = KeyGenerateUtil.sm4Decrypt(keyDecrypt, s);
            System.err.println("应急内容 -- ：" + sm4Decrypt);
            strBuilder.append("应急内容 -- ：").append(sm4Decrypt).append("\n");
            startIndex = startIndex + emergencyContentLength;

            // 文字滚动倍速长度
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            int textScrollLength = Jtt808Utils.bcdBytes2Int(bytes);
            System.err.println("文字滚动倍速长度 -- ：" + textScrollLength);
            strBuilder.append("文字滚动倍速长度 -- ：").append(textScrollLength).append("\n");
            startIndex = startIndex + 1;

            // 文字滚动倍速
            bytes = BinaryUtil.subArray(dataBytes, startIndex, textScrollLength);
            System.err.println("文字滚动倍速 -- ：" + new String(bytes, StandardCharsets.UTF_8));
            strBuilder.append("文字滚动倍速 -- ：").append(new String(bytes, StandardCharsets.UTF_8)).append("\n");
            startIndex = startIndex + textScrollLength;

            // 文字播放间隔时间
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 2);
            int textInterval = Jtt808Utils.bcdBytes2Int(bytes);
            System.err.println("文字播放间隔时间 -- ：" + textInterval);
            strBuilder.append("文字播放间隔时间 -- ：").append(textInterval).append("\n");
            startIndex = startIndex + 2;

            // 字体倍率长度
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            int fontScaleLength = Jtt808Utils.bcdBytes2Int(bytes);
            System.err.println("字体倍率长度 -- ：" + fontScaleLength);
            strBuilder.append("字体倍率长度 -- ：").append(fontScaleLength).append("\n");
            startIndex = startIndex + 1;

            // 字体倍率
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            System.err.println("字体倍率 -- ：" + new String(bytes, StandardCharsets.UTF_8));
            strBuilder.append("字体倍率 -- ：").append(new String(bytes, StandardCharsets.UTF_8)).append("\n");
        });

        return str.toString();
    }


    /**
     * 信息发布报文撤回测试
     *
     * @param hexStr 十六进制 str
     * @return {@link String}
     */
    public String taskBackTest(String hexStr) {
        StringBuilder str = commonProcess(hexStr, (strBuilder, dataBytes) -> {
            int startIndex = 0;

            // 节目撤回任务ID长度
            byte[] bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            int taskIdLength = Jtt808Utils.bcdBytes2Int(bytes);
            System.err.println("节目撤回任务ID长度 -- ：" + taskIdLength);
            strBuilder.append("节目撤回任务ID长度 -- ：").append(taskIdLength).append("\n");
            startIndex = startIndex + 1;

            // 节目撤回任务ID
            bytes = BinaryUtil.subArray(dataBytes, startIndex, taskIdLength);
            System.err.println("节目撤回任务ID -- ：" + Jtt808Utils.bcdBytes2Long(bytes));
            strBuilder.append("节目撤回任务ID -- ：").append(Jtt808Utils.bcdBytes2Long(bytes)).append("\n");
            startIndex = startIndex + taskIdLength;

            // 节目撤回推送任务ID长度
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            int pushIdLength = Jtt808Utils.bcdBytes2Int(bytes);
            System.err.println("节目撤回推送任务ID长度 -- ：" + pushIdLength);
            strBuilder.append("节目撤回推送任务ID长度 -- ：").append(pushIdLength).append("\n");
            startIndex = startIndex + 1;

            // 节目撤回推送任务ID
            bytes = BinaryUtil.subArray(dataBytes, startIndex, pushIdLength);
            System.err.println("节目撤回推送任务ID -- ：" + Jtt808Utils.bcdBytes2Long(bytes));
            strBuilder.append("节目撤回推送任务ID -- ：").append(Jtt808Utils.bcdBytes2Long(bytes)).append("\n");
            startIndex = startIndex + pushIdLength;

            // 数据
            dataBytes = BinaryUtil.subArray(dataBytes, startIndex, dataBytes.length - startIndex - 1);
            startIndex = 0;

            // 信息发布任务ID长度
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            int infoIdLength = Jtt808Utils.bcdBytes2Int(bytes);
            System.err.println("信息发布任务ID长度 -- ：" + infoIdLength);
            strBuilder.append("信息发布任务ID长度 -- ：").append(infoIdLength).append("\n");
            startIndex = startIndex + 1;

            // 信息发布任务ID
            bytes = BinaryUtil.subArray(dataBytes, startIndex, infoIdLength);
            System.err.println("信息发布任务ID -- ：" + Jtt808Utils.bcdBytes2Long(bytes));
            strBuilder.append("信息发布任务ID -- ：").append(Jtt808Utils.bcdBytes2Long(bytes)).append("\n");
            startIndex = startIndex + infoIdLength;

            // 信息发布推送任务ID长度
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            int infoPushIdLength = Jtt808Utils.bcdBytes2Int(bytes);
            System.err.println("信息发布推送任务ID长度 -- ：" + infoPushIdLength);
            strBuilder.append("信息发布推送任务ID长度 -- ：").append(infoPushIdLength).append("\n");
            startIndex = startIndex + 1;

            // 信息发布推送任务ID
            bytes = BinaryUtil.subArray(dataBytes, startIndex, infoPushIdLength);
            System.err.println("信息发布推送任务ID -- ：" + Jtt808Utils.bcdBytes2Long(bytes));
            strBuilder.append("信息发布推送任务ID -- ：").append(Jtt808Utils.bcdBytes2Long(bytes)).append("\n");
            startIndex = startIndex + infoPushIdLength;

            // 撤回节目个数
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            int backCount = Jtt808Utils.bcdBytes2Int(bytes);
            System.err.println("撤回节目个数 -- ：" + backCount);
            strBuilder.append("撤回节目个数 -- ：").append(backCount).append("\n");
            startIndex = startIndex + 1;

            // 节目撤回列表
            for (int i = 0; i < backCount; i++) {
                // 节目ID长度
                bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
                int programIdLength = Jtt808Utils.bcdBytes2Int(bytes);
                System.err.println("节目ID长度 -- ：" + programIdLength);
                strBuilder.append("节目ID长度 -- ：").append(programIdLength).append("\n");
                startIndex = startIndex + 1;

                // 节目ID
                bytes = BinaryUtil.subArray(dataBytes, startIndex, programIdLength);
                System.err.println("节目ID -- ：" + Jtt808Utils.bcdBytes2Long(bytes));
                strBuilder.append("节目ID -- ：").append(Jtt808Utils.bcdBytes2Long(bytes)).append("\n");
                startIndex = startIndex + programIdLength;
            }

        });
        return str.toString();
    }

    /**
     * 应急发布撤回测试
     *
     * @param hexStr 十六进制 str
     * @return {@link String}
     */
    public String emergencyBackTest(String hexStr) {
        StringBuilder str = commonProcess(hexStr, (strBuilder, dataBytes) -> {
            int startIndex = 0;
            // 应急撤回任务ID长度
            byte[] bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            int taskIdLength = Jtt808Utils.bcdBytes2Int(bytes);
            System.err.println("应急撤回任务ID长度 -- ：" + taskIdLength);
            strBuilder.append("应急撤回任务ID长度 -- ：").append(taskIdLength).append("\n");
            startIndex = startIndex + 1;

            // 应急撤回任务ID
            bytes = BinaryUtil.subArray(dataBytes, startIndex, taskIdLength);
            System.err.println("应急撤回任务ID -- ：" + Jtt808Utils.bcdBytes2Long(bytes));
            strBuilder.append("应急撤回任务ID -- ：").append(Jtt808Utils.bcdBytes2Long(bytes)).append("\n");
            startIndex = startIndex + taskIdLength;

            // 应急撤回推送任务ID长度
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            int pushIdLength = Jtt808Utils.bcdBytes2Int(bytes);
            System.err.println("应急撤回推送任务ID长度 -- ：" + pushIdLength);
            strBuilder.append("应急撤回推送任务ID长度 -- ：").append(pushIdLength).append("\n");
            startIndex = startIndex + 1;

            // 应急撤回推送任务ID
            bytes = BinaryUtil.subArray(dataBytes, startIndex, pushIdLength);
            System.err.println("应急撤回推送任务ID -- ：" + Jtt808Utils.bcdBytes2Long(bytes));
            strBuilder.append("应急撤回推送任务ID -- ：").append(Jtt808Utils.bcdBytes2Long(bytes)).append("\n");
            startIndex = startIndex + pushIdLength;

            // 数据解密
            dataBytes = BinaryUtil.subArray(dataBytes, startIndex, dataBytes.length - startIndex - 1);
            startIndex = 0;

            // 应急发布任务ID长度
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            int emergencyIdLength = Jtt808Utils.bcdBytes2Int(bytes);
            System.err.println("应急任务ID长度 -- ：" + emergencyIdLength);
            strBuilder.append("应急任务ID长度 -- ：").append(emergencyIdLength).append("\n");
            startIndex = startIndex + 1;

            // 应急推送任务ID长度
            bytes = BinaryUtil.subArray(dataBytes, startIndex, emergencyIdLength);
            long emergencyPushId = Jtt808Utils.bcdBytes2Long(bytes);
            System.err.println("应急任务ID -- ：" + emergencyPushId);
            strBuilder.append("应急任务ID -- ：").append(emergencyPushId).append("\n");
            startIndex = startIndex + emergencyIdLength;

            // 应急推送任务ID长度
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            int emergencyTaskIdLength = Jtt808Utils.bcdBytes2Int(bytes);
            System.err.println("应急推送任务ID长度 -- ：" + emergencyTaskIdLength);
            strBuilder.append("应急推送任务ID长度 -- ：").append(emergencyTaskIdLength).append("\n");
            startIndex = startIndex + 1;

            // 应急推送任务ID
            bytes = BinaryUtil.subArray(dataBytes, startIndex, emergencyTaskIdLength);
            System.err.println("应急推送任务ID -- ：" + Jtt808Utils.bcdBytes2Long(bytes));
            strBuilder.append("应急推送任务ID -- ：").append(Jtt808Utils.bcdBytes2Long(bytes)).append("\n");
        });
        return str.toString();
    }

    /**
     * 发班信息报文测试
     *
     * @param hexStr           十六进制 str
     * @param devicePrivateKey 设备私钥
     * @return {@link String}
     */
    public String dispatchTest(String hexStr, String devicePrivateKey) {
        StringBuilder str = commonProcess(hexStr, (strBuilder, data) ->
                commonProcess(data, strBuilder, devicePrivateKey, dataBytes -> {
                    int startIndex = 0;
                    byte[] bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
                    int routeCodeLength = Jtt808Utils.byteToInt(bytes);
                    System.err.println("线路代码长度 -- ：" + routeCodeLength);
                    strBuilder.append("线路代码长度 -- ：").append(routeCodeLength).append("\n");
                    startIndex = startIndex + 1;

                    bytes = BinaryUtil.subArray(dataBytes, startIndex, routeCodeLength);
                    System.err.println("线路代码 -- ：" + new String(bytes));
                    strBuilder.append("线路代码 -- ：").append(new String(bytes)).append("\n");
                    startIndex = startIndex + routeCodeLength;

                    bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
                    int routeNameLength = Jtt808Utils.byteToInt(bytes);
                    System.err.println("线路名称长度 -- ：" + routeNameLength);
                    strBuilder.append("线路名称长度 -- ：").append(routeNameLength).append("\n");
                    startIndex = startIndex + 1;


                    bytes = BinaryUtil.subArray(dataBytes, startIndex, routeNameLength);
                    System.err.println("线路名称：" + new String(bytes, StandardCharsets.UTF_8));
                    strBuilder.append("线路名称 -- ：").append(new String(bytes, StandardCharsets.UTF_8)).append("\n");
                    startIndex = startIndex + routeNameLength;

                    bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
                    int busNoLength = Jtt808Utils.byteToInt(bytes);
                    System.err.println("车辆编号长度 -- ：" + busNoLength);
                    strBuilder.append("车辆编号长度 -- ：").append(busNoLength).append("\n");
                    startIndex = startIndex + 1;

                    bytes = BinaryUtil.subArray(dataBytes, startIndex, busNoLength);
                    System.err.println("车辆编号：" + new String(bytes, StandardCharsets.UTF_8));
                    strBuilder.append("车辆编号 -- ：").append(new String(bytes, StandardCharsets.UTF_8)).append("\n");
                    startIndex = startIndex + busNoLength;

                    bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
                    int selfNumberingLength = Jtt808Utils.byteToInt(bytes);
                    System.err.println("车辆号长度 -- ：" + selfNumberingLength);
                    strBuilder.append("车辆号长度 -- ：").append(selfNumberingLength).append("\n");
                    startIndex = startIndex + 1;

                    bytes = BinaryUtil.subArray(dataBytes, startIndex, selfNumberingLength);
                    System.err.println("车辆号：" + new String(bytes, StandardCharsets.UTF_8));
                    strBuilder.append("车辆号 -- ：").append(new String(bytes, StandardCharsets.UTF_8)).append("\n");
                    startIndex = startIndex + selfNumberingLength;

                    bytes = BinaryUtil.subArray(dataBytes, startIndex, 2);
                    System.err.println("发车时间 -- ：" + Jtt808Utils.bcdBytes2HexStr(bytes));
                    strBuilder.append("发车时间 -- ：").append(Jtt808Utils.bcdBytes2HexStr(bytes)).append("\n");
                    startIndex = startIndex + 2;

                    bytes = BinaryUtil.subArray(dataBytes, startIndex, 6);
                    System.err.println("发车完整时间 -- ：" + Jtt808Utils.bcdBytes2HexStr(bytes));
                    strBuilder.append("发车完整时间 -- ：").append(Jtt808Utils.bcdBytes2HexStr(bytes)).append("\n");
                }));

        return str.toString();
    }

    /**
     * 静态线路测试
     *
     * @param hexStr           十六进制 str
     * @param devicePrivateKey 设备私钥
     * @return {@link String}
     */
    public String staticTest(String hexStr, String devicePrivateKey) {
        StringBuilder str = commonProcess(hexStr, (strBuilder, dataBytes) -> {
            int startIndex = 0;
            // 动态秘钥
            byte[] bytes = BinaryUtil.subArray(dataBytes, startIndex, 113);
            String keyEncrypt = Jtt808Utils.byte2Hex(bytes);
            System.err.println("动态秘钥加密 -- : " + keyEncrypt);
            strBuilder.append("动态秘钥加密 -- : ").append(keyEncrypt).append("\n");

            byte[] s3 = KeyGenerateUtil.sm2Decrypt(devicePrivateKey, keyEncrypt);
            String keyDecrypt = Jtt808Utils.bcdBytes2HexStr(s3);
            System.err.println("动态秘钥解密 -- : " + keyDecrypt);
            strBuilder.append("动态秘钥解密 -- : ").append(keyDecrypt).append("\n");
            startIndex = startIndex + 113;

            bytes = BinaryUtil.subArray(dataBytes, startIndex, dataBytes.length - startIndex - 1);
            String lineEncrypt = Jtt808Utils.byte2Hex(bytes);
            System.err.println("线路加密字符串：" + lineEncrypt);
            strBuilder.append("线路加密字符串 -- : ").append(lineEncrypt).append("\n");
            startIndex = 0;

            dataBytes = Jtt808Utils.hex2byte(KeyGenerateUtil.sm4Decrypt(keyDecrypt, lineEncrypt));
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            // 线路数量
            int lineCount = Jtt808Utils.byteToInt(bytes);
            System.err.println("线路数量 -- ：" + lineCount);
            startIndex = 1;
            for (int i = 0; i < lineCount; i++) {
                bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
                int routeCodeLength = Jtt808Utils.byteToInt(bytes);
                System.err.println("线路代码长度 -- ：" + routeCodeLength);
                strBuilder.append("线路代码长度 -- ：").append(routeCodeLength).append("\n");
                startIndex = startIndex + 1;

                bytes = BinaryUtil.subArray(dataBytes, startIndex, routeCodeLength);
                System.err.println("线路代码 -- ：" + new String(bytes));
                strBuilder.append("线路代码 -- ：").append(new String(bytes)).append("\n");
                startIndex = startIndex + routeCodeLength;

                bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
                int routeNameLength = Jtt808Utils.byteToInt(bytes);
                System.err.println("线路名称长度 -- ：" + routeNameLength);
                strBuilder.append("线路名称长度 -- ：").append(routeNameLength).append("\n");
                startIndex = startIndex + 1;

                bytes = BinaryUtil.subArray(dataBytes, startIndex, routeNameLength);
                System.err.println("线路名称：" + new String(bytes, StandardCharsets.UTF_8));
                strBuilder.append("线路名称 -- ：").append(new String(bytes, StandardCharsets.UTF_8)).append("\n");
                startIndex = startIndex + routeNameLength;

                bytes = BinaryUtil.subArray(dataBytes, startIndex, 2);
                System.err.println("首班时间 -- ：" + Jtt808Utils.bcdBytes2HexStr(bytes));
                strBuilder.append("首班时间 -- ：").append(Jtt808Utils.bcdBytes2HexStr(bytes)).append("\n");
                startIndex = startIndex + 2;

                bytes = BinaryUtil.subArray(dataBytes, startIndex, 2);
                System.err.println("末班时间 -- ：" + Jtt808Utils.bcdBytes2HexStr(bytes));

                // 站台数据
                startIndex = startIndex + 2;
                bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
                int stationCount = Jtt808Utils.byteToInt(bytes);
                System.err.println();
                System.err.println("站台数量 -- ：" + stationCount);
                strBuilder.append("站台数量 -- ：").append(stationCount).append("\n");
                startIndex = startIndex + 1;
                for (int j = 0; j < stationCount; j++) {
                    bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
                    int stationNameLength = Jtt808Utils.bcdBytes2Int(bytes);
                    System.err.println("站台名称长度 -- ：" + stationNameLength);
                    strBuilder.append("站台名称长度 -- ：").append(stationNameLength).append("\n");
                    startIndex = startIndex + 1;

                    bytes = BinaryUtil.subArray(dataBytes, startIndex, stationNameLength);
                    System.err.println("站台名称 -- ：" + new String(bytes, StandardCharsets.UTF_8));
                    strBuilder.append("站台名称 -- ：").append(new String(bytes, StandardCharsets.UTF_8)).append("\n");
                    startIndex = startIndex + stationNameLength;

                    bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
                    int stationIdLength = Jtt808Utils.bcdBytes2Int(bytes);
                    System.err.println("站台ID长度 -- ：" + stationIdLength);
                    strBuilder.append("站台ID长度 -- ：").append(stationIdLength).append("\n");
                    startIndex = startIndex + 1;

                    bytes = BinaryUtil.subArray(dataBytes, startIndex, stationIdLength);
                    System.err.println("站台ID -- ：" + new String(bytes, StandardCharsets.UTF_8));
                    strBuilder.append("站台ID -- ：").append(new String(bytes, StandardCharsets.UTF_8)).append("\n");
                    startIndex = startIndex + stationIdLength;

                    bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
                    int stopCodeLength = Jtt808Utils.bcdBytes2Int(bytes);
                    System.err.println("站点唯一编号长度 -- ：" + stopCodeLength);
                    strBuilder.append("站点唯一编号长度 -- ：").append(stopCodeLength).append("\n");
                    startIndex = startIndex + 1;

                    bytes = BinaryUtil.subArray(dataBytes, startIndex, stopCodeLength);
                    System.err.println("站点唯一编号 -- ：" + new String(bytes, StandardCharsets.UTF_8));
                    strBuilder.append("站点唯一编号 -- ：").append(new String(bytes, StandardCharsets.UTF_8)).append("\n");
                    startIndex = startIndex + stopCodeLength;

                    bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
                    System.err.println("站点顺序 -- ：" + Jtt808Utils.bcdBytes2Int(bytes));
                    strBuilder.append("站点顺序 -- ：").append(Jtt808Utils.bcdBytes2Int(bytes)).append("\n");
                    startIndex = startIndex + 1;
                }
            }
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            int currentStationLength = Jtt808Utils.byteToInt(bytes);
            System.err.println("当前站点名称长度" + currentStationLength);
            strBuilder.append("当前站点名称长度").append(currentStationLength).append("\n");
            startIndex += 1;

            if (currentStationLength > 0) {
                bytes = BinaryUtil.subArray(dataBytes, startIndex, currentStationLength);
                System.err.println("当前站点名称 -- ：" + new String(bytes, StandardCharsets.UTF_8));
                strBuilder.append("当前站点名称 -- ：").append(new String(bytes, StandardCharsets.UTF_8)).append("\n");
                startIndex += currentStationLength;
            }

            bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            int nextStationLength = Jtt808Utils.byteToInt(bytes);
            System.err.println("当前站点ID长度 -- ：" + nextStationLength);
            strBuilder.append("当前站点ID长度 -- ：").append(nextStationLength).append("\n");
            startIndex += 1;

            if (nextStationLength > 0) {
                bytes = BinaryUtil.subArray(dataBytes, startIndex, nextStationLength);
                System.err.println("当前站点ID -- ：" + new String(bytes, StandardCharsets.UTF_8));
                strBuilder.append("当前站点ID -- ：").append(new String(bytes, StandardCharsets.UTF_8)).append("\n");
                startIndex += nextStationLength;
            }
        });
        return str.toString();
    }

    /**
     * 动态车辆信息测试
     *
     * @param hexStr           十六进制 str
     * @param devicePrivateKey 设备私钥
     */
    public String adInfoTest(String hexStr, String devicePrivateKey) {
        StringBuilder str = commonProcess(hexStr, (strBuilder, data) -> {
            commonProcess(data, strBuilder, devicePrivateKey, dataBytes -> {
                int startIndex = 0;
                byte[] bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
                // 线路数量
                int lineCount = Jtt808Utils.byteToInt(bytes);
                System.err.println("线路数量 -- ：" + lineCount);
                strBuilder.append("线路数量 -- ：").append(lineCount).append("\n");

                startIndex = 1;
                for (int i = 0; i < lineCount; i++) {
                    bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
                    int routeCodeLength = Jtt808Utils.bcdBytes2Int(bytes);
                    System.err.println("线路代码长度 -- ：" + routeCodeLength);
                    strBuilder.append("线路代码长度 -- ：").append(routeCodeLength).append("\n");
                    startIndex = startIndex + 1;

                    bytes = BinaryUtil.subArray(dataBytes, startIndex, routeCodeLength);
                    System.err.println("线路代码 -- ：" + new String(bytes));
                    strBuilder.append("线路代码 -- ：").append(new String(bytes)).append("\n");
                    startIndex = startIndex + routeCodeLength;

                    bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
                    int routeNameLength = Jtt808Utils.bcdBytes2Int(bytes);
                    System.err.println("线路名称长度 -- ：" + routeNameLength);
                    strBuilder.append("线路名称长度 -- ：").append(routeNameLength).append("\n");
                    startIndex = startIndex + 1;

                    // 线路名称
                    if (routeNameLength > 0) {
                        bytes = BinaryUtil.subArray(dataBytes, startIndex, routeNameLength);
                        System.err.println("线路名称 -- ：" + new String(bytes, StandardCharsets.UTF_8));
                        strBuilder.append("线路名称 -- ：").append(new String(bytes, StandardCharsets.UTF_8)).append("\n");
                        startIndex = startIndex + routeNameLength;
                    }

                    // 当前站台ID长度
                    bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
                    int currentStationIdLength = Jtt808Utils.bcdBytes2Int(bytes);
                    System.err.println("当前站台ID长度 -- ：" + currentStationIdLength);
                    strBuilder.append("当前站台ID长度 -- ：").append(currentStationIdLength).append("\n");
                    startIndex = startIndex + 1;

                    // 当前站台ID
                    bytes = BinaryUtil.subArray(dataBytes, startIndex, currentStationIdLength);
                    System.err.println("当前站台ID -- ：" + new String(bytes, StandardCharsets.UTF_8));
                    strBuilder.append("当前站台ID -- ：").append(new String(bytes, StandardCharsets.UTF_8)).append("\n");
                    startIndex = startIndex + currentStationIdLength;

                    // 当前站点唯一编号长度
                    bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
                    int currentStopCodeLength = Jtt808Utils.bcdBytes2Int(bytes);
                    System.err.println("当前站点唯一编号长度 -- ：" + currentStopCodeLength);
                    strBuilder.append("当前站点唯一编号长度 -- ：").append(currentStopCodeLength).append("\n");
                    startIndex = startIndex + 1;

                    // 当前站点唯一编号
                    bytes = BinaryUtil.subArray(dataBytes, startIndex, currentStopCodeLength);
                    System.err.println("当前站点唯一编号 -- ：" + new String(bytes, StandardCharsets.UTF_8));
                    strBuilder.append("当前站点唯一编号 -- ：").append(new String(bytes, StandardCharsets.UTF_8)).append("\n");
                    startIndex = startIndex + currentStopCodeLength;

                    // 未到达车辆数量
                    bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
                    int unArrivedCount = Jtt808Utils.bcdBytes2Int(bytes);
                    System.err.println("未到达当前站点车辆数量 -- ：" + unArrivedCount);
                    strBuilder.append("未到达当前站点车辆数量 -- ：").append(unArrivedCount).append("\n");
                    startIndex = startIndex + 1;
                    startIndex = getStartIndex(strBuilder, dataBytes, startIndex, unArrivedCount);

                    // 未到达终点站车辆数量
                    bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
                    int unArrivedEndCount = Jtt808Utils.bcdBytes2Int(bytes);
                    System.err.println("未到达终点站车辆数量 -- ：" + unArrivedEndCount);
                    strBuilder.append("未到达终点站车辆数量 -- ：").append(unArrivedEndCount).append("\n");
                    startIndex = startIndex + 1;
                    startIndex = getStartIndex(strBuilder, dataBytes, startIndex, unArrivedEndCount);
                }
            });
        });
        return str.toString();
    }

    /**
     * 软件升级测试
     *
     * @param hexStr           十六进制 str
     * @param devicePrivateKey 设备私钥
     * @return {@link String}
     */
    public String appTest(String hexStr, String devicePrivateKey) {
        StringBuilder str = commonProcess(hexStr, (strBuilder, dataBytes) -> {
            int startIndex = 0;
            // 升级任务ID长度
            byte[] bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            int taskIdLength = Jtt808Utils.byteToInt(bytes);
            System.err.println("升级任务ID长度 -- ：" + taskIdLength);
            strBuilder.append("升级任务ID长度 -- ：").append(taskIdLength).append("\n");
            startIndex = startIndex + 1;

            // 升级任务ID
            bytes = BinaryUtil.subArray(dataBytes, startIndex, taskIdLength);
            System.err.println("升级任务ID -- ：" + Jtt808Utils.bcdBytes2Long(bytes));
            strBuilder.append("升级任务ID -- ：").append(Jtt808Utils.bcdBytes2Long(bytes)).append("\n");
            startIndex = startIndex + taskIdLength;

            // 升级推送任务ID长度
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            int pushTaskIdLength = Jtt808Utils.byteToInt(bytes);
            System.err.println("升级推送任务ID长度 -- ：" + pushTaskIdLength);
            strBuilder.append("升级推送任务ID长度 -- ：").append(pushTaskIdLength).append("\n");
            startIndex = startIndex + 1;

            // 升级推送任务ID
            bytes = BinaryUtil.subArray(dataBytes, startIndex, pushTaskIdLength);
            System.err.println("升级推送任务ID -- ：" + Jtt808Utils.bcdBytes2Long(bytes));
            strBuilder.append("升级推送任务ID -- ：").append(Jtt808Utils.bcdBytes2Long(bytes)).append("\n");
            startIndex = startIndex + pushTaskIdLength;

            // 动态秘钥
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 113);
            String keyEncrypt = Jtt808Utils.byte2Hex(bytes);
            System.err.println("动态秘钥加密 -- : " + keyEncrypt);
            strBuilder.append("动态秘钥加密 -- : ").append(keyEncrypt).append("\n");
            startIndex = startIndex + 113;

            byte[] s3 = KeyGenerateUtil.sm2Decrypt(devicePrivateKey, keyEncrypt);
            String keyDecrypt = Jtt808Utils.bcdBytes2HexStr(s3);
            System.err.println("动态秘钥解密 -- : " + keyDecrypt);
            strBuilder.append("动态秘钥解密 -- : ").append(keyDecrypt).append("\n");

            dataBytes = BinaryUtil.subArray(dataBytes, startIndex, dataBytes.length - startIndex - 1);
            startIndex = 0;

            // 软件数量
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            int softwareCount = Jtt808Utils.bcdBytes2Int(bytes);
            System.err.println("软件数量 -- ：" + softwareCount);
            strBuilder.append("软件数量 -- ：").append(softwareCount).append("\n");
            startIndex = startIndex + 1;

            for (int i = 0; i < softwareCount; i++) {
                // 软件名称长度
                bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
                int softwareNameLength = Jtt808Utils.bcdBytes2Int(bytes);
                System.err.println("软件名称长度 -- ：" + softwareNameLength);
                strBuilder.append("软件名称长度 -- ：").append(softwareNameLength).append("\n");
                startIndex = startIndex + 1;

                // 软件名称
                bytes = BinaryUtil.subArray(dataBytes, startIndex, softwareNameLength);
                System.err.println("软件名称 -- ：" + new String(bytes, StandardCharsets.UTF_8));
                strBuilder.append("软件名称 -- ：").append(new String(bytes, StandardCharsets.UTF_8)).append("\n");
                startIndex = startIndex + softwareNameLength;

                // 软件版本长度
                bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
                int softwareVersionLength = Jtt808Utils.bcdBytes2Int(bytes);
                System.err.println("软件版本长度 -- ：" + softwareVersionLength);
                strBuilder.append("软件版本长度 -- ：").append(softwareVersionLength).append("\n");
                startIndex = startIndex + 1;

                // 软件版本
                bytes = BinaryUtil.subArray(dataBytes, startIndex, softwareVersionLength);
                System.err.println("软件版本 -- ：" + new String(bytes, StandardCharsets.UTF_8));
                strBuilder.append("软件版本 -- ：").append(new String(bytes, StandardCharsets.UTF_8)).append("\n");
                startIndex = startIndex + softwareVersionLength;

                // 升级包地址长度
                bytes = BinaryUtil.subArray(dataBytes, startIndex, 2);
                int upgradeUrlLength = Jtt808Utils.bcdBytes2Int(bytes);
                System.err.println("升级包地址长度 -- ：" + upgradeUrlLength);
                strBuilder.append("升级包地址长度 -- ：").append(upgradeUrlLength).append("\n");
                startIndex = startIndex + 2;

                // 升级包地址
                bytes = BinaryUtil.subArray(dataBytes, startIndex, upgradeUrlLength);
                System.err.println("升级包地址 -- ：" + new String(bytes, StandardCharsets.UTF_8));
                strBuilder.append("升级包地址 -- ：").append(new String(bytes, StandardCharsets.UTF_8)).append("\n");
                startIndex = startIndex + upgradeUrlLength;

                // 软件包名长度
                bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
                int softwarePkgNameLength = Jtt808Utils.bcdBytes2Int(bytes);
                System.err.println("软件包名长度 -- ：" + softwarePkgNameLength);
                strBuilder.append("软件包名长度 -- ：").append(softwarePkgNameLength).append("\n");
                startIndex = startIndex + 1;
                if (softwarePkgNameLength > 0) {
                    // 软件包名
                    bytes = BinaryUtil.subArray(dataBytes, startIndex, softwarePkgNameLength);
                    System.err.println("软件包名 -- ：" + new String(bytes, StandardCharsets.UTF_8));
                    strBuilder.append("软件包名 -- ：").append(new String(bytes, StandardCharsets.UTF_8)).append("\n");
                    startIndex = startIndex + softwarePkgNameLength;
                }

                // 签名
                bytes = BinaryUtil.subArray(dataBytes, startIndex, 32);
                String sign = Jtt808Utils.byte2Hex(bytes);
                System.err.println("签名 -- ：" + sign);
                strBuilder.append("签名 -- ：").append(sign).append("\n");
                startIndex = startIndex + 32;
            }
        });
        return str.toString();
    }

    /**
     * 业务指令测试
     *
     * @param hexStr 十六进制 str
     * @return {@link String}
     */
    public static String bizActionTest(String hexStr) {
        StringBuilder str = commonProcess(hexStr, (strBuilder, dataBytes) -> {
            int startIndex = 0;

            // 业务指令任务ID长度
            byte[] bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            int taskIdLength = Jtt808Utils.byteToInt(bytes);
            System.err.println("业务指令任务ID长度 -- ：" + taskIdLength);
            strBuilder.append("业务指令任务ID长度 -- ：").append(taskIdLength).append("\n");
            startIndex = startIndex + 1;

            // 业务指令任务ID
            bytes = BinaryUtil.subArray(dataBytes, startIndex, taskIdLength);
            System.err.println("业务指令任务ID -- ：" + Jtt808Utils.bcdBytes2Long(bytes));
            strBuilder.append("业务指令任务ID -- ：").append(Jtt808Utils.bcdBytes2Long(bytes)).append("\n");
            startIndex = startIndex + taskIdLength;

            // 业务指令推送任务ID长度
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            int pushTaskIdLength = Jtt808Utils.byteToInt(bytes);
            System.err.println("业务指令推送任务ID长度 -- ：" + pushTaskIdLength);
            strBuilder.append("业务指令推送任务ID长度 -- ：").append(pushTaskIdLength).append("\n");
            startIndex = startIndex + 1;

            // 业务指令推送任务ID
            bytes = BinaryUtil.subArray(dataBytes, startIndex, pushTaskIdLength);
            System.err.println("业务指令推送任务ID -- ：" + Jtt808Utils.bcdBytes2Long(bytes));
            strBuilder.append("业务指令推送任务ID -- ：").append(Jtt808Utils.bcdBytes2Long(bytes)).append("\n");
            startIndex = startIndex + pushTaskIdLength;

            dataBytes = BinaryUtil.subArray(dataBytes, startIndex, dataBytes.length - startIndex - 1);
            startIndex = 0;

            // 指令条数
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            int instructionCount = Jtt808Utils.bcdBytes2Int(bytes);
            System.err.println("指令条数 -- ：" + instructionCount);
            strBuilder.append("指令条数 -- ：").append(instructionCount).append("\n");
            startIndex = startIndex + 1;

            for (int i = 0; i < instructionCount; i++) {
                // 指令类型
                bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
                int instructionType = Jtt808Utils.byteToInt(bytes);
                System.err.println("指令类型 -- ：" + instructionType);
                strBuilder.append("指令类型 -- ：").append(instructionType).append("\n");
                startIndex = startIndex + 1;

                // 文本内容长度
                bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
                int textContentLength = Jtt808Utils.bcdBytes2Int(bytes);
                System.err.println("文本内容长度 -- ：" + textContentLength);
                strBuilder.append("文本内容长度 -- ：").append(textContentLength).append("\n");
                startIndex = startIndex + 1;

                // 文本内容
                if (textContentLength > 0) {
                    bytes = BinaryUtil.subArray(dataBytes, startIndex, textContentLength);
                    System.err.println("文本内容 -- ：" + new String(bytes, StandardCharsets.UTF_8));
                    strBuilder.append("文本内容 -- ：").append(new String(bytes, StandardCharsets.UTF_8)).append("\n");
                    startIndex = startIndex + textContentLength;
                }
            }
        });
        return str.toString();
    }

    /**
     * 指令测试
     *
     * @param hexStr           十六进制 str
     * @param devicePrivateKey 设备私钥
     * @return {@link String}
     */
    public static String actionTest(String hexStr, String devicePrivateKey) {
        StringBuilder str = commonProcess(hexStr, (strBuilder, dataBytes) -> {
            int startIndex = 0;

            // 控制指令任务ID长度
            byte[] bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            int taskIdLength = Jtt808Utils.byteToInt(bytes);
            System.err.println("控制指令任务ID长度 -- ：" + taskIdLength);
            strBuilder.append("控制指令任务ID长度 -- ：").append(taskIdLength).append("\n");
            startIndex = startIndex + 1;

            // 控制指令任务ID
            bytes = BinaryUtil.subArray(dataBytes, startIndex, taskIdLength);
            System.err.println("控制指令任务ID -- ：" + Jtt808Utils.bcdBytes2Long(bytes));
            strBuilder.append("控制指令任务ID -- ：").append(Jtt808Utils.bcdBytes2Long(bytes)).append("\n");
            startIndex = startIndex + taskIdLength;

            // 控制指令推送任务ID长度
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            int pushTaskIdLength = Jtt808Utils.byteToInt(bytes);
            System.err.println("控制指令推送任务ID长度 -- ：" + pushTaskIdLength);
            strBuilder.append("控制指令推送任务ID长度 -- ：").append(pushTaskIdLength).append("\n");
            startIndex = startIndex + 1;

            // 控制指令推送任务ID
            bytes = BinaryUtil.subArray(dataBytes, startIndex, pushTaskIdLength);
            System.err.println("控制指令推送任务ID -- ：" + Jtt808Utils.bcdBytes2Long(bytes));
            strBuilder.append("控制指令推送任务ID -- ：").append(Jtt808Utils.bcdBytes2Long(bytes)).append("\n");
            startIndex = startIndex + pushTaskIdLength;

            // 动态秘钥
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 113);
            String keyEncrypt = Jtt808Utils.byte2Hex(bytes);
            System.err.println("动态秘钥加密 -- : " + keyEncrypt);
            strBuilder.append("动态秘钥加密 -- : ").append(keyEncrypt).append("\n");
            startIndex = startIndex + 113;

            byte[] s3 = KeyGenerateUtil.sm2Decrypt(devicePrivateKey, keyEncrypt);
            String keyDecrypt = Jtt808Utils.bcdBytes2HexStr(s3);
            System.err.println("动态秘钥解密 -- : " + keyDecrypt);
            strBuilder.append("动态秘钥解密 -- : ").append(keyDecrypt).append("\n");

            bytes = BinaryUtil.subArray(dataBytes, startIndex, dataBytes.length - startIndex - 1);
            String lineEncrypt = Jtt808Utils.byte2Hex(bytes);
            System.err.println("加密字符串：" + lineEncrypt);
            strBuilder.append("加密字符串 -- : ").append(lineEncrypt).append("\n");

            // 解密
            dataBytes = Jtt808Utils.hex2byte(KeyGenerateUtil.sm4Decrypt(keyDecrypt, lineEncrypt));
            startIndex = 0;

            // 指令条数
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            int instructionCount = Jtt808Utils.bcdBytes2Int(bytes);
            System.err.println("指令条数 -- ：" + instructionCount);
            strBuilder.append("指令条数 -- ：").append(instructionCount).append("\n");
            startIndex = startIndex + 1;

            for (int i = 0; i < instructionCount; i++) {
                // 控制指令类型
                bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
                int controlType = Jtt808Utils.byteToInt(bytes);
                System.err.println("控制指令类型 -- ：" + controlType);
                strBuilder.append("控制指令类型 -- ：").append(controlType).append("\n");
                startIndex = startIndex + 1;

                // 控制指令值
                bytes = BinaryUtil.subArray(dataBytes, startIndex, 2);
                int controlValue = Jtt808Utils.bcdBytes2Int(bytes);
                System.err.println("控制指令值 -- ：" + controlValue);
                strBuilder.append("控制指令值 -- ：").append(controlValue).append("\n");
                startIndex = startIndex + 2;
            }
        });
        return str.toString();
    }

    private int getStartIndex(StringBuilder strBuilder, byte[] dataBytes, int startIndex, int unArrivedEndCount) {
        byte[] bytes;
        for (int i = 0; i < unArrivedEndCount; i++) {
            // 车辆序号
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            System.err.println("车辆序号 -- ：" + bytes[0]);
            strBuilder.append("车辆序号 -- ：").append(bytes[0]).append("\n");
            startIndex = startIndex + 1;

            // 停靠状态
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            System.err.println("停靠状态 -- ：" + bytes[0]);
            strBuilder.append("停靠状态 -- ：").append(bytes[0]).append("\n");
            startIndex = startIndex + 1;

            // 预计到达当前站时间
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 2);
            System.err.println("预计到达当前站时间 -- ：" + Jtt808Utils.bcdBytes2Int(bytes));
            strBuilder.append("预计到达当前站时间 -- ：").append(Jtt808Utils.bcdBytes2Int(bytes)).append("\n");
            startIndex = startIndex + 2;

            // 到达站数
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            byte arrivedCount = bytes[0];
            System.err.println("到达站数 -- ：" + arrivedCount);
            strBuilder.append("到达站数 -- ：").append(arrivedCount).append("\n");
            startIndex = startIndex + 1;
        }
        return startIndex;
    }

    /**
     * 公共处理
     *
     * @param hexStr     十六进制 str
     * @param biConsumer BI 消费者
     * @return {@link StringBuilder}
     */
    private StringBuilder commonProcess(String hexStr, BiConsumer<StringBuilder, byte[]> biConsumer) {
        StringBuilder stringBuilder = new StringBuilder();
        byte[] dataBytes = BinaryUtil.removeMessageHeader(hexStr);
        // 下发时间
        byte[] bytes = BinaryUtil.subArray(dataBytes, 0, 6);
        String s1 = Jtt808Utils.bcdBytes2HexStr(bytes);
        System.err.println("下发时间 -- : " + s1);
        stringBuilder.append("下发时间 -- : ").append(s1).append("\n");

        // 设备编号
        bytes = BinaryUtil.subArray(dataBytes, 6, 36);
        String s2 = new String(bytes, StandardCharsets.UTF_8);
        System.err.println("设备编号 -- " + s2);
        stringBuilder.append("设备编号 -- ").append(s2).append("\n");
        biConsumer.accept(stringBuilder, BinaryUtil.subArray(dataBytes, 42, dataBytes.length - 42));
        return stringBuilder;
    }

    @NotNull
    private String programWeek(@NotNull String programWeek) {
        StringBuilder str = new StringBuilder();
        // 补齐8位
        for (int i = 0; i < 8 - programWeek.length(); i++) {
            str.append("0");
        }
        programWeek = str + programWeek;
        List<String> weekList = new ArrayList<>();
        String[] split = programWeek.split("");
        String k = "1";
        for (int i = 0; i < split.length; i++) {
            String s1 = split[i];
            if (i == 1 && Objects.equals(k, s1)) {
                weekList.add("星期一");
            }
            if (i == 2 && Objects.equals(k, s1)) {
                weekList.add("星期二");
            }
            if (i == 3 && Objects.equals(k, s1)) {
                weekList.add("星期三");
            }
            if (i == 4 && Objects.equals(k, s1)) {
                weekList.add("星期四");
            }
            if (i == 5 && Objects.equals(k, s1)) {
                weekList.add("星期五");
            }
            if (i == 6 && Objects.equals(k, s1)) {
                weekList.add("星期六");
            }
            if (i == 7 && Objects.equals(k, s1)) {
                weekList.add("星期天");
            }
        }
        return String.join(",", weekList);
    }

    /**
     * 设备秘钥交互解密测试
     *
     * @param hexStr           十六进制 str
     * @param devicePrivateKey 设备私钥
     * @return {@link String}
     */
    public String keyInteractionTest(String hexStr, String devicePrivateKey) {
        StringBuilder str = commonProcess(hexStr, (strBuilder, dataBytes) ->
                commonProcess(dataBytes, strBuilder, devicePrivateKey, dataBytes1 -> {
                    int startIndex = 0;
                    // 账号名称长度
                    byte[] bytes = BinaryUtil.subArray(dataBytes1, startIndex, 1);
                    int accountNameLength = Jtt808Utils.byteToInt(bytes);
                    System.err.println("账号名称长度 -- ：" + accountNameLength);
                    strBuilder.append("账号名称长度 -- ：").append(accountNameLength).append("\n");
                    startIndex = startIndex + 1;

                    // 账号名称
                    bytes = BinaryUtil.subArray(dataBytes1, startIndex, accountNameLength);
                    System.err.println("账号名称 -- ：" + new String(bytes, StandardCharsets.UTF_8));
                    strBuilder.append("账号名称 -- ：").append(new String(bytes, StandardCharsets.UTF_8)).append("\n");
                    startIndex = startIndex + accountNameLength;

                    // 密码长度
                    bytes = BinaryUtil.subArray(dataBytes1, startIndex, 1);
                    int passwordLength = Jtt808Utils.byteToInt(bytes);
                    System.err.println("密码长度 -- ：" + passwordLength);
                    strBuilder.append("密码长度 -- ：").append(passwordLength).append("\n");
                    startIndex = startIndex + 1;

                    // 密码
                    bytes = BinaryUtil.subArray(dataBytes1, startIndex, passwordLength);
                    System.err.println("密码 -- ：" + new String(bytes, StandardCharsets.UTF_8));
                    strBuilder.append("密码 -- ：").append(new String(bytes, StandardCharsets.UTF_8)).append("\n");
                    startIndex = startIndex + passwordLength;

                    // 接入地址长度
                    bytes = BinaryUtil.subArray(dataBytes1, startIndex, 1);
                    int accessAddressLength = Jtt808Utils.byteToInt(bytes);
                    System.err.println("接入地址长度 -- ：" + accessAddressLength);
                    strBuilder.append("接入地址长度 -- ：").append(accessAddressLength).append("\n");
                    startIndex = startIndex + 1;

                    // 接入地址
                    bytes = BinaryUtil.subArray(dataBytes1, startIndex, accessAddressLength);
                    System.err.println("接入地址 -- ：" + new String(bytes, StandardCharsets.UTF_8));
                    strBuilder.append("接入地址 -- ：").append(new String(bytes, StandardCharsets.UTF_8)).append("\n");
                    startIndex = startIndex + accessAddressLength;

                    // 系统SM2公钥长度
                    bytes = BinaryUtil.subArray(dataBytes1, startIndex, 1);
                    int systemSm2PublicKeyLength = Jtt808Utils.byteToInt(bytes);
                    System.err.println("系统SM2公钥长度 -- ：" + systemSm2PublicKeyLength);
                    strBuilder.append("系统SM2公钥长度 -- ：").append(systemSm2PublicKeyLength).append("\n");
                    startIndex = startIndex + 1;

                    // 系统SM2公钥
                    bytes = BinaryUtil.subArray(dataBytes1, startIndex, systemSm2PublicKeyLength);
                    System.err.println("系统SM2公钥 -- ：" + Jtt808Utils.bcdBytes2HexStr(bytes));
                    strBuilder.append("系统SM2公钥 -- ：").append(Jtt808Utils.bcdBytes2HexStr(bytes)).append("\n");
                }));
        return str.toString();
    }

    /**
     * 下发日志指令解密测试
     *
     * @param hexStr 十六进制 str
     * @return {@link String}
     */
    @NotNull
    public String deviceLogIssued(String hexStr) {
        StringBuilder str = commonProcess(hexStr, (strBuilder, dataBytes) -> {
            int startIndex = 0;
            // 日志生成开始时间
            byte[] bytes = BinaryUtil.subArray(dataBytes, startIndex, 6);
            String logStartTime = Jtt808Utils.bcdBytes2HexStr(bytes);
            System.err.println("日志生成开始时间 -- : " + logStartTime);
            strBuilder.append("日志生成开始时间 -- : ").append(logStartTime).append("\n");
            startIndex = startIndex + 6;

            // 日志生成结束时间
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 6);
            String logEndTime = Jtt808Utils.bcdBytes2HexStr(bytes);
            System.err.println("日志生成结束时间 -- : " + logEndTime);
            strBuilder.append("日志生成结束时间 -- : ").append(logEndTime).append("\n");
            startIndex = startIndex + 6;

            // 日志类型
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            int logType = Jtt808Utils.byteToInt(bytes);
            System.err.println("日志类型 -- ：" + logType);
            strBuilder.append("日志类型 -- ：").append(logType).append("\n");
        });
        return str.toString();
    }

    /**
     * 天气预报测试
     *
     * @param hexStr           十六进制 str
     * @param devicePrivateKey 设备私钥
     * @return {@link String}
     */
    public String weatherForecastTest(String hexStr, String devicePrivateKey) {
        StringBuilder str = commonProcess(hexStr, (strBuilder, dataBytes) ->
                commonProcess(dataBytes, strBuilder, devicePrivateKey, dataBytes1 -> {
                    int startIndex = 0;
                    // 风力等级长度
                    byte[] bytes = BinaryUtil.subArray(dataBytes1, startIndex, 1);
                    int windLevelLength = Jtt808Utils.bcdBytes2Int(bytes);
                    System.err.println("风力等级长度 -- ：" + windLevelLength);
                    strBuilder.append("风力等级长度 -- ：").append(windLevelLength).append("\n");
                    startIndex = startIndex + 1;

                    // 风力等级
                    bytes = BinaryUtil.subArray(dataBytes1, startIndex, windLevelLength);
                    System.err.println("风力等级 -- ：" + new String(bytes, StandardCharsets.UTF_8));
                    strBuilder.append("风力等级 -- ：").append(new String(bytes, StandardCharsets.UTF_8)).append("\n");
                    startIndex = startIndex + windLevelLength;

                    // 温度长度
                    bytes = BinaryUtil.subArray(dataBytes1, startIndex, 1);
                    int temperatureLength = Jtt808Utils.bcdBytes2Int(bytes);
                    System.err.println("温度长度 -- : " + temperatureLength);
                    strBuilder.append("温度长度 -- : ").append(temperatureLength).append("\n");
                    startIndex = startIndex + 1;

                    // 温度
                    bytes = BinaryUtil.subArray(dataBytes1, startIndex, temperatureLength);
                    System.err.println("温度 -- : " + new String(bytes, StandardCharsets.UTF_8));
                    strBuilder.append("温度 -- : ").append(new String(bytes, StandardCharsets.UTF_8)).append("\n");
                    startIndex = startIndex + temperatureLength;

                    // 天气长度
                    bytes = BinaryUtil.subArray(dataBytes1, startIndex, 2);
                    int weatherLength = Jtt808Utils.bcdBytes2Int(bytes);
                    System.err.println("天气长度 -- ：" + weatherLength);
                    strBuilder.append("天气长度 -- ：").append(weatherLength).append("\n");
                    startIndex = startIndex + 2;

                    // 天气
                    bytes = BinaryUtil.subArray(dataBytes1, startIndex, weatherLength);
                    System.err.println("天气 -- ：" + new String(bytes, StandardCharsets.UTF_8));
                    strBuilder.append("天气 -- ：").append(new String(bytes, StandardCharsets.UTF_8)).append("\n");
                    startIndex = startIndex + weatherLength;

                    // 天气图片
                    bytes = BinaryUtil.subArray(dataBytes1, startIndex, dataBytes1.length - startIndex - 1);
                    String weatherImg = new String(bytes, StandardCharsets.UTF_8);
                    System.err.println("天气图片 -- ：" + weatherImg);
                    strBuilder.append("天气图片 -- ：").append(weatherImg).append("\n");
                }));
        return str.toString();
    }

    /**
     * 驾驶员图片测试
     *
     * @param hexStr           十六进制 str
     * @param devicePrivateKey 设备私钥
     * @return {@link String }
     */
    public static String driverPictureTest(String hexStr, String devicePrivateKey) {
        StringBuilder stringBuilder = new StringBuilder();
        byte[] dataBytes = BinaryUtil.removeMessageHeader(hexStr);
        // 下发时间
        byte[] bytes = BinaryUtil.subArray(dataBytes, 0, 6);
        String time = Jtt808Utils.bcdBytes2HexStr(bytes);
        stringBuilder.append("下发时间 -- : ").append(time).append("\n");
        System.err.println("下发时间 -- : " + time);
        // 司机照片
        bytes = BinaryUtil.subArray(dataBytes, 6, dataBytes.length - 7);
        SM4 sm4 = new SM4(HexUtil.decodeHex(devicePrivateKey));

        byte[] decrypt = sm4.decrypt(bytes);
        stringBuilder.append("解密信息 -- : " + Jtt808Utils.byte2Hex(decrypt)).append("\n");
        System.err.println("解密信息 -- : " + Jtt808Utils.byte2Hex(decrypt));

        int startIndex = 0;
        // 司机照片长度
        bytes = BinaryUtil.subArray(decrypt, startIndex, 2);
        int driverPictureLength = Jtt808Utils.bcdBytes2Int(bytes);
        System.err.println("司机照片长度 -- : " + driverPictureLength);
        stringBuilder.append("司机照片长度 -- : ").append(driverPictureLength).append("\n");
        startIndex += 2;

        if (driverPictureLength > 0) {
            // 司机照片
            bytes = BinaryUtil.subArray(decrypt, startIndex, driverPictureLength);
            System.err.println("司机照片 -- : " + new String(bytes, StandardCharsets.UTF_8));
            stringBuilder.append("司机照片 -- : ").append(new String(bytes, StandardCharsets.UTF_8)).append("\n");
            startIndex += driverPictureLength;
        }

        // 司机服务号长度
        bytes = BinaryUtil.subArray(decrypt, startIndex, 2);
        int driverServiceNoLength = Jtt808Utils.bcdBytes2Int(bytes);
        System.err.println("司机服务号长度 -- : " + driverServiceNoLength);
        stringBuilder.append("司机服务号长度 -- : ").append(driverServiceNoLength).append("\n");
        startIndex += 2;

        // 司机服务号
        bytes = BinaryUtil.subArray(decrypt, startIndex, driverServiceNoLength);
        System.err.println("司机服务号 -- : " + new String(bytes, StandardCharsets.UTF_8));
        stringBuilder.append("司机服务号 -- : ").append(new String(bytes, StandardCharsets.UTF_8)).append("\n");
        return stringBuilder.toString();
    }

    /**
     * 航班测试
     *
     * @param hexStr           十六进制 str
     * @param devicePrivateKey 设备私钥
     * @return {@link String }
     */
    public static String flightTest(String hexStr, String devicePrivateKey) {
        StringBuilder stringBuilder = new StringBuilder();
        byte[] dataBytes = BinaryUtil.removeMessageHeader(hexStr);
        int startIndex = 0;
        // 下发时间
        byte[] bytes = BinaryUtil.subArray(dataBytes, startIndex, 6);
        String time = Jtt808Utils.bcdBytes2HexStr(bytes);
        stringBuilder.append("下发时间 -- : ").append(time).append("\n");
        System.err.println("下发时间 -- : " + time);
        startIndex += 6;

        // 当前页码
        bytes = BinaryUtil.subArray(dataBytes, startIndex, 2);
        System.err.println("当前页码 -- : " + Jtt808Utils.bcdBytes2Long(bytes));
        stringBuilder.append("当前页码 -- : ").append(Jtt808Utils.bcdBytes2Long(bytes)).append("\n");
        startIndex += 2;

        // 每页数据量
        bytes = BinaryUtil.subArray(dataBytes, startIndex, 2);
        long pageSize = Jtt808Utils.bcdBytes2Long(bytes);
        System.err.println("每页数据量 -- : " + pageSize);
        stringBuilder.append("每页数据量 -- : ").append(pageSize).append("\n");
        startIndex += 2;

        // 总数据量
        bytes = BinaryUtil.subArray(dataBytes, startIndex, 4);
        long totalData = Jtt808Utils.bcdBytes2Long(bytes);
        System.err.println("总数据量 -- : " + totalData);
        stringBuilder.append("总数据量 -- : ").append(totalData).append("\n");
        startIndex += 4;

        // 当前页航班数据量
        bytes = BinaryUtil.subArray(dataBytes, startIndex, 2);
        long currentPageDataSize = Jtt808Utils.bcdBytes2Long(bytes);
        System.err.println("当前页航班数据量 -- : " + currentPageDataSize);
        stringBuilder.append("当前页航班数据量 -- : ").append(currentPageDataSize).append("\n");
        startIndex += 2;

        String s = KeyGenerateUtil.sm4Decrypt(devicePrivateKey, Jtt808Utils.byte2Hex(BinaryUtil.subArray(dataBytes, startIndex, dataBytes.length - startIndex - 1)));

        dataBytes = Jtt808Utils.hex2byte(s);
        startIndex = 0;

        for (int i = 0; i < currentPageDataSize; i++) {

            // 航班数据编号
            startIndex = notNull(stringBuilder, dataBytes, startIndex, false, "航班数据编号");

            // 航班号
            startIndex = notNull(stringBuilder, dataBytes, startIndex, false, "航班号");

            // 航空公司代码
            startIndex = notNull(stringBuilder, dataBytes, startIndex, false, "航空公司代码");

            // 出发地机场三字码
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 3);
            System.err.println("出发地机场三字码 -- : " + new String(bytes, StandardCharsets.UTF_8));
            stringBuilder.append("出发地机场三字码 -- : ").append(new String(bytes, StandardCharsets.UTF_8)).append("\n");
            startIndex += 3;

            // 目的地机场三字码
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 3);
            System.err.println("目的地机场三字码 -- : " + new String(bytes, StandardCharsets.UTF_8));
            stringBuilder.append("目的地机场三字码 -- : ").append(new String(bytes, StandardCharsets.UTF_8)).append("\n");
            startIndex += 3;

            // 出发城市
            startIndex = notNull(stringBuilder, dataBytes, startIndex, false, "出发城市");

            // 出发机场
            startIndex = notNull(stringBuilder, dataBytes, startIndex, false, "出发机场");

            // 出发国家
            startIndex = notNull(stringBuilder, dataBytes, startIndex, false, "出发国家");

            // 出发省份
            startIndex = notNull(stringBuilder, dataBytes, startIndex, false, "出发省份");

            // 出发航站楼
            startIndex = notNull(stringBuilder, dataBytes, startIndex, false, "出发航站楼");

            // 到达城市
            startIndex = notNull(stringBuilder, dataBytes, startIndex, false, "到达城市");

            // 到达机场
            startIndex = notNull(stringBuilder, dataBytes, startIndex, false, "到达机场");

            // 到达国家
            startIndex = notNull(stringBuilder, dataBytes, startIndex, false, "到达国家");

            // 到达省份
            startIndex = notNull(stringBuilder, dataBytes, startIndex, false, "到达省份");

            // 到达航站楼
            startIndex = notNull(stringBuilder, dataBytes, startIndex, false, "到达航站楼");

            // 计划起飞时间
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 7);
            System.err.println("计划起飞时间 -- : " + Jtt808Utils.byte2Hex(bytes));
            stringBuilder.append("计划起飞时间 -- : ").append(Jtt808Utils.byte2Hex(bytes)).append("\n");
            startIndex += 7;

            // 计划到达时间
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 7);
            System.err.println("计划到达时间 -- : " + Jtt808Utils.byte2Hex(bytes));
            stringBuilder.append("计划到达时间 -- : ").append(Jtt808Utils.byte2Hex(bytes)).append("\n");
            startIndex += 7;

            // 实际起飞时间
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 7);
            System.err.println("实际起飞时间 -- : " + Jtt808Utils.byte2Hex(bytes));
            stringBuilder.append("实际起飞时间 -- : ").append(Jtt808Utils.byte2Hex(bytes)).append("\n");
            startIndex += 7;

            // 实际到达时间
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 7);
            System.err.println("实际到达时间 -- : " + Jtt808Utils.byte2Hex(bytes));
            stringBuilder.append("实际到达时间 -- : ").append(Jtt808Utils.byte2Hex(bytes)).append("\n");
            startIndex += 7;

            // 出发地时区
            startIndex = notNull(stringBuilder, dataBytes, startIndex, false, "出发地时区");

            // 目的地时区
            startIndex = notNull(stringBuilder, dataBytes, startIndex, false, "目的地时区");

            // 班期
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 7);
            System.err.println("班期 -- : " + Jtt808Utils.byte2Hex(bytes));
            stringBuilder.append("班期 -- : ").append(Jtt808Utils.byte2Hex(bytes)).append("\n");
            startIndex += 7;

            // 经停次数
            startIndex = notNull(stringBuilder, dataBytes, startIndex, true, "经停次数");

            // 航班属性
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            System.err.println("航班属性 -- : " + Jtt808Utils.byte2Hex(bytes));
            stringBuilder.append("航班属性 -- : ").append(Jtt808Utils.byte2Hex(bytes)).append("\n");
            startIndex += 1;

            // 进出港
            startIndex = notNull(stringBuilder, dataBytes, startIndex, true, "进出港");

            // 乘坐人
            startIndex = notNull(stringBuilder, dataBytes, startIndex, true, "乘坐人");

            // 航程
            startIndex = notNull(stringBuilder, dataBytes, startIndex, true, "航程");

            // 座位数
            startIndex = notNull(stringBuilder, dataBytes, startIndex, true, "座位数");

            // 航段
            startIndex = notNull(stringBuilder, dataBytes, startIndex, true, "航段");

            // 状态
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            System.err.println("状态 -- : " + Jtt808Utils.byte2Hex(bytes));
            stringBuilder.append("状态 -- : ").append(Jtt808Utils.byte2Hex(bytes)).append("\n");
            startIndex += 1;

            // 数据天
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 4);
            System.err.println("数据天 -- : " + Jtt808Utils.byte2Hex(bytes));
            stringBuilder.append("数据天 -- : ").append(Jtt808Utils.byte2Hex(bytes)).append("\n");
            startIndex += 4;
        }
        return stringBuilder.toString();
    }

    private int notNull(StringBuilder stringBuilder, byte[] dataBytes, int startIndex, boolean isInt, String name) {
        byte[] bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
        int i = Jtt808Utils.bcdBytes2Int(bytes);
        System.err.println(name + "长度 -- : " + i);
        stringBuilder.append(name).append("长度 -- : ").append(i).append("\n");
        startIndex += 1;
        if (i > 0) {
            bytes = BinaryUtil.subArray(dataBytes, startIndex, i);
            System.err.println(name + " -- : " + (isInt ? Jtt808Utils.bcdBytes2Int(bytes) : new String(bytes, StandardCharsets.UTF_8)));
            stringBuilder.append(name).append(" -- : ").append(isInt ? Jtt808Utils.bcdBytes2Int(bytes) : new String(bytes, StandardCharsets.UTF_8)).append("\n");
            startIndex += i;
        }
        return startIndex;
    }

    /**
     * 屏幕尺寸测试
     *
     * @param hexStr           十六进制 str
     * @param devicePrivateKey 设备私钥
     * @return {@link String }
     */
    public static String screenSizeTest(String hexStr, String devicePrivateKey) {
        StringBuilder str = commonProcess(hexStr, (strBuilder, dataBytes) -> {
            int startIndex = 0;
            // 设备尺寸长度
            byte[] bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            int windLevelLength = Jtt808Utils.bcdBytes2Int(bytes);
            System.err.println("设备尺寸长度 -- ：" + windLevelLength);
            strBuilder.append("设备尺寸长度 -- ：").append(windLevelLength).append("\n");
            startIndex = startIndex + 1;

            // 设备尺寸
            bytes = BinaryUtil.subArray(dataBytes, startIndex, windLevelLength);
            System.err.println("设备尺寸 -- ：" + new String(bytes, StandardCharsets.UTF_8));
            strBuilder.append("设备尺寸 -- ：").append(new String(bytes, StandardCharsets.UTF_8)).append("\n");
            startIndex = startIndex + windLevelLength;

            // 屏幕类型长度
            bytes = BinaryUtil.subArray(dataBytes, startIndex, 1);
            int temperatureLength = Jtt808Utils.bcdBytes2Int(bytes);
            System.err.println("屏幕类型长度 -- ：" + temperatureLength);
            strBuilder.append("屏幕类型长度 -- ：").append(temperatureLength).append("\n");
            startIndex = startIndex + 1;

            // 屏幕类型
            bytes = BinaryUtil.subArray(dataBytes, startIndex, temperatureLength);
            System.err.println("屏幕类型 -- ：" + new String(bytes, StandardCharsets.UTF_8));
            strBuilder.append("屏幕类型 -- ：").append(new String(bytes, StandardCharsets.UTF_8)).append("\n");
        });
        return str.toString();
    }

    /**
     * 通用流程
     *
     * @param dataBytes        数据字节
     * @param strBuilder       STR 生成器
     * @param devicePrivateKey 设备私钥
     * @param consumer         消费者
     */
    private void commonProcess(byte[] dataBytes, @NotNull StringBuilder strBuilder, String devicePrivateKey, @NotNull Consumer<byte[]> consumer) {
        int startIndex = 0;
        // 动态秘钥
        byte[] bytes = BinaryUtil.subArray(dataBytes, startIndex, 113);
        String keyEncrypt = Jtt808Utils.byte2Hex(bytes);
        System.err.println("动态秘钥加密 -- : " + keyEncrypt);
        strBuilder.append("动态秘钥加密 -- : ").append(keyEncrypt).append("\n");
        startIndex = startIndex + 113;

        byte[] s3 = KeyGenerateUtil.sm2Decrypt(devicePrivateKey, keyEncrypt);
        String keyDecrypt = Jtt808Utils.bcdBytes2HexStr(s3);
        System.err.println("动态秘钥解密 -- : " + keyDecrypt);
        strBuilder.append("动态秘钥解密 -- : ").append(keyDecrypt).append("\n");

        bytes = BinaryUtil.subArray(dataBytes, startIndex, dataBytes.length - startIndex - 1);
        String lineEncrypt = Jtt808Utils.byte2Hex(bytes);
        System.err.println("加密字符串：" + lineEncrypt);
        strBuilder.append("加密字符串 -- : ").append(lineEncrypt).append("\n");

        // 解密
        String sm4Decrypt = KeyGenerateUtil.sm4Decrypt(keyDecrypt, lineEncrypt);
        strBuilder.append("解密结果 -- : ").append(sm4Decrypt).append("\n");
        System.err.println("解密结果 -- : " + sm4Decrypt);
        dataBytes = Jtt808Utils.hex2byte(sm4Decrypt);
        consumer.accept(dataBytes);
    }
}
